/**
 *
 * Copyright (C) 2008  Igor Vdovichenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * Though a sincere effort has been made to deliver a professional,
 * quality product,the library itself is distributed WITHOUT ANY WARRANTY;
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 */
package com.vin.scriptutils.utils;

import java.util.Collection;
import java.util.LinkedList;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

/**
 *
 * @author igor
 */
public class UnixCommandBuilder {

    private Collection<Node> cmndElements;
    private final Character separator;

    public static class Command extends Nodes {

        private Command(final String command) {
            nodes(command);
        }
    }

    public static class Arguments extends Nodes {

        private Arguments(final String... arguments) {
            nodes(arguments);
        }
    }

    public static class ArgumentsQuoted extends Nodes {

        private ArgumentsQuoted(final String... arguments) {
            super(new QuoteQuotingStrategy());
            nodes(arguments);
        }
    }

    public static class ArgumentsEsc extends Nodes {

        private ArgumentsEsc(final String... arguments) {
            nodesEsc(arguments);
        }
    }

    public static class ArgumentsQuotedEsc extends Nodes {

        private ArgumentsQuotedEsc(final String... arguments) {
            super(new QuoteQuotingStrategy());
            nodesEsc(arguments);
        }
    }

    public UnixCommandBuilder() {
        this.separator = ' ';
        reset();
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof UnixCommandBuilder)) {
            return false;
        }
        return new EqualsBuilder().append(toCommandLine(), ((UnixCommandBuilder) obj).toCommandLine()).isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(toCommandLine()).toHashCode();
    }

    public void reset() {
        this.cmndElements = new LinkedList<Node>();
    }

    public String toCommandLine() {
        StringBuilder sb = new StringBuilder();
        for (Node element : this.cmndElements) {
            if (sb.length() > 0) {
                sb.append(this.separator);
            }
            sb.append(element);
        }
        return sb.toString().trim();
    }

    public UnixCommandBuilder command(String arguments) {
        cmndElements.addAll(new Command(arguments).getNodes());
        return this;
    }

    public UnixCommandBuilder argv(String... arguments) {
        cmndElements.addAll(new Arguments(arguments).getNodes());
        return this;
    }

    public UnixCommandBuilder argvIf(boolean flag, String... arguments) {
        if (flag) {
            cmndElements.addAll(new Arguments(arguments).getNodes());
        }
        return this;
    }

    public UnixCommandBuilder argvQ(String... arguments) {
        cmndElements.addAll(new ArgumentsQuoted(arguments).getNodes());
        return this;
    }

    public UnixCommandBuilder argvEsc(String... arguments) {
        cmndElements.addAll(new ArgumentsEsc(arguments).getNodes());
        return this;
    }

    /**
     * Helper functions
     */
    /**
     * @return "&&"
     */
    public UnixCommandBuilder ifSucceeded() {
        cmndElements.addAll(new Command("&&").getNodes());
        return this;
    }

    /**
     * @return "||"
     */
    public UnixCommandBuilder ifFailed() {
        cmndElements.addAll(new Command("||").getNodes());
        return this;
    }

    /**
     * @return "|"
     */
    public UnixCommandBuilder pipeOutputTo() {
        cmndElements.addAll(new Command("|").getNodes());
        return this;
    }

    /**
     * @return "("
     */
    public UnixCommandBuilder beginList() {
        cmndElements.addAll(new Command("(").getNodes());
        return this;
    }

    /**
     * @return ")"
     */
    public UnixCommandBuilder endList() {
        cmndElements.addAll(new Command(")").getNodes());
        return this;
    }

    /**
     * @return "{"
     */
    public UnixCommandBuilder beginGroup() {
        cmndElements.addAll(new Command("{").getNodes());
        return this;
    }

    /**
     * @return "}"
     */
    public UnixCommandBuilder endGroup() {
        cmndElements.addAll(new Command("; }").getNodes());
        return this;
    }

    /**
     * @return ";"
     */
    public UnixCommandBuilder inSequence() {
        cmndElements.addAll(new Command(";").getNodes());
        return this;
    }

    /**
     * @return "<"
     */
    public UnixCommandBuilder redirectIn() {
        cmndElements.addAll(new Command("<").getNodes());
        return this;
    }

    /**
     * @return ">"
     */
    public UnixCommandBuilder redirectOut() {
        cmndElements.addAll(new Command(">").getNodes());
        return this;
    }

    /**
     * @return ">>"
     */
    public UnixCommandBuilder appendOut() {
        cmndElements.addAll(new Command(">>").getNodes());
        return this;
    }

    /**
     *
     * @return "<<"
     */
    public UnixCommandBuilder appendIn() {
        cmndElements.addAll(new Command("<<").getNodes());
        return this;
    }

    /**
     * @return "2>"
     */
    public UnixCommandBuilder redirectErr() {
        cmndElements.addAll(new Command("2>").getNodes());
        return this;
    }

    /**
     * @return "2>&1"
     */
    public UnixCommandBuilder redirectErrToOut() {
        cmndElements.addAll(new Command("2>&1").getNodes());
        return this;
    }

    /**
     * @return ">&2"
     */
    public UnixCommandBuilder redirectOutToErr() {
        cmndElements.addAll(new Command(">&2").getNodes());
        return this;
    }

    /**
     * @return "<&-"
     */
    public UnixCommandBuilder closeInput() {
        cmndElements.addAll(new Command("<&-").getNodes());
        return this;
    }

    /**
     * @return ">&-"
     */
    public UnixCommandBuilder closeOutput() {
        cmndElements.addAll(new Command(">&-").getNodes());
        return this;
    }

    /**
     * @return "\\\n"
     */
    public UnixCommandBuilder continueLine() {
        cmndElements.addAll(new Command("\\\n").getNodes());
        return this;
    }

    /**
     * @return "&"
     */
    public UnixCommandBuilder inBackground() {
        cmndElements.addAll(new Command("&").getNodes());
        return this;
    }
}
